//////////////////////////////////////////////////////////////////////////
//
// GAM203
// Mesh Dwarf
// MeshDwarf.cpp
// 
// Grant Johnson
// Qantm College
// 27/10/2010
//
//////////////////////////////////////////////////////////////////////////

#include "MeshDwarf.h"

#include <d3dx9.h>

MeshDwarf::MeshDwarf()
: m_pMesh(NULL)
{
}

MeshDwarf::~MeshDwarf()
{
	// Release any textures we created
	for(UINT i=0; i<m_segmentCount; ++i)
	{
		m_materials[i].second->Release();
	}
	m_materials.clear();

	// Release mesh if it was loaded
	if (m_pMesh)
	{
		m_pMesh->Release();
		m_pMesh = NULL;
	}
}

bool MeshDwarf::CreateObject(IDirect3DDevice9* a_pDevice, char* a_pTexFileName)
{
	//Ensure that the device given is valid
	if (!a_pDevice)
	{
		return false;
	}
	//The texture file name here is a mesh filename, so if NULL, return false, cannot create
	if(!a_pTexFileName)
	{
		return false;
	}

	// Load the .x file
	ID3DXBuffer* pMaterialBuf = NULL;
	ID3DXBuffer* pEffectBuf = NULL;

	HRESULT result = D3DXLoadMeshFromX(a_pTexFileName, D3DXMESH_DYNAMIC, a_pDevice, NULL, &pMaterialBuf, &pEffectBuf, &m_segmentCount, &m_pMesh);
	if (result != D3D_OK)
	{
		return false;
	}

	DWORD* pVertices = NULL;
	m_pMesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pVertices);

	D3DXComputeBoundingBox((D3DXVECTOR3*)pVertices, m_pMesh->GetNumVertices(), D3DXGetFVFVertexSize(m_pMesh->GetFVF()), &m_aabb.GetMin(), &m_aabb.GetMax());

	m_pMesh->UnlockVertexBuffer();

	// We have to cast the buffer's data into the type we need (since the buffer is just arbitrary data)
	// In this case it is an array of D3DXMATERIAL structs, which are just a {D3DMATERIAL9, char*}
	D3DXMATERIAL* pMaterials;
	pMaterials = (D3DXMATERIAL*)pMaterialBuf->GetBufferPointer();

	// For each segmentIndex in the mesh, read its material data
	for (DWORD i = 0; i < m_segmentCount; ++i)
	{
		D3DXMATERIAL& segmentMaterialData = pMaterials[i];

		// Load the texture on this segmentIndex
		// The texture filenames don't come with any path information, filename only :(
		char texPath[256];

		sprintf_s(texPath, 256, "%s%s", "media/",segmentMaterialData.pTextureFilename);

		// Create a new texture with this path + filename
		IDirect3DTexture9* pNewTex = NULL;

		result = D3DXCreateTextureFromFile(a_pDevice, texPath, &pNewTex);

		if (result != D3D_OK)
		{
			// Failed to load - output some debug information, but continue on
			OutputDebugString("Failed to load texture:");
			OutputDebugString(texPath);
			// pNewTex will remain NULL, which is ok (we can safely select a NULL texture when rendering)
		}

		// Store this segmentIndex's material data; we copy-by-value this D3DMATERIAL9 into a new pair
		// (If we only stored a ptr to segmentMaterialData.MatD3D, that would be dangerous because the buffer is about to be released below!)
		MaterialTexturePair newMtlTexPair(segmentMaterialData.MatD3D, pNewTex);
		m_materials.push_back(newMtlTexPair);
	}

	// Release these since we don't need them anymore
	if (pMaterialBuf) pMaterialBuf->Release();
	if (pEffectBuf) pEffectBuf->Release();

	return true;
}

void MeshDwarf::Render(float a_dt, IDirect3DDevice9* a_pDevice)
{
	//Ensure we have a valid device and mesh to draw
	if (a_pDevice && m_pMesh)
	{
		// Set up our world transform
		a_pDevice->SetTransform(D3DTS_WORLD, &m_worldMatrix);

		// Draw each segmentIndex of our mesh
		for (DWORD segmentIndex = 0; segmentIndex < m_segmentCount; ++segmentIndex)
		{
			// The "first" part of the pair is our D3DMATERIAL9 struct
			a_pDevice->SetMaterial(&m_materials[segmentIndex].first);
			// The "second" part of the pair is the texture pointer (which is ok if it's NULL)
			a_pDevice->SetTexture(0, m_materials[segmentIndex].second);

			// Draw the mesh segment
			HRESULT result = m_pMesh->DrawSubset(segmentIndex);
			if(result != D3D_OK)
			{
				return;
			}
		}
	}
	//Reset texture
	a_pDevice->SetTexture(0, NULL);
}

